----------------------------------------------------------------------------------
-- Company: 			StrathSat-R
-- Engineer: 			Thomas Parry
-- 
-- Create Date:    	21:19:40 09/06/2012 
-- Design Name: 		SD host testing interface with UART
-- Module Name:    	sd_uart_test - behavioral 
-- Project Name: 		FPGA Data Storage
-- Target Devices: 	Spartan 3E - Papillio One
-- Tool versions: 
-- Description: 
--
-- Dependencies: 
--
-- Revision: 
-- Revision 0.01 - File Created
-- Additional Comments: 
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;

-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;


entity sd_uart_test is
	port 
	(
		Clk_Ext 		: in  	std_logic;
		Reset 		: in  	std_logic;
		
		Rx 			: in  	std_logic;
		Tx 			: out  	std_logic;
		
		Sd_Clk_Out	: out  	std_logic;
      Sd_Cmd 		: inout  std_logic;
      Sd_Data 		: inout  std_logic;
		
		Resp_Found	: out		std_logic;
		Data_Done	: out		std_logic
	);
end sd_uart_test;

architecture behavioral of sd_uart_test is

---- components

-- UART transmitter
component uart_tx is
	port 
	(            
		Data_In 					:	in 	std_logic_vector(7 downto 0);
      Write_Buffer 			: 	in 	std_logic;
      Reset_Buffer 			: 	in 	std_logic;
      En_16_X_Baud 			: 	in 	std_logic;
      Serial_Out 				: 	out 	std_logic;
      Buffer_Full 			: 	out 	std_logic;
      Buffer_Half_Full		: 	out 	std_logic;
      Clk 						: 	in		std_logic
	);
end component; 

-- UART receiver
component uart_rx is
	port 
	(      
		Serial_In 				: 	in		std_logic;
      Read_Buffer 			: 	in  	std_logic;
      Reset_Buffer 			: 	in		std_logic;
      En_16_X_Baud 			: 	in  	std_logic;
      Clk 						: 	in  	std_logic;
      Data_Out 				: 	out 	std_logic_vector(7 downto 0);
      Buffer_Data_Present 	: 	out 	std_logic;
		Buffer_Half_Full 		: 	out 	std_logic;
      Buffer_Full 			: 	out 	std_logic
	);
end component; 
  
-- clock managers 
component DCM32TO96
	port
	(
		CLKIN_IN 				: 	in 	std_logic;
		RST_IN 					: 	in 	std_logic;          
		CLKFX_OUT 				: 	out 	std_logic;
		CLK0_OUT 				: 	out 	std_logic;
		LOCKED_OUT 				: 	out 	std_logic
	);
end component;

component DCM32TO50
	port
	(
		CLKIN_IN 				: 	in 	std_logic;
		RST_IN 					: 	in 	std_logic;          
		CLKFX_OUT 				: 	out 	std_logic;
		CLK0_OUT 				: 	out 	std_logic;
		LOCKED_OUT 				: 	out 	std_logic
	);
end component;

-- SD card host
component host is
	generic
	(
		CMD_LENGTH				:	integer := 6;
		ARGUMENT_LENGTH		:	integer := 32;
		CMD_CRC_LENGTH			:	integer := 7;
		DATA_LENGTH				:	integer := 4096;
		DATA_INPUT_WIDTH		:	integer := 8;
		DATA_CRC_LENGTH		:	integer := 16
	);
   port 
	( 
		Clk 						: 	in  		std_logic;
		Reset						:	in			std_logic;
      Data 						: 	in  		std_logic_vector(DATA_INPUT_WIDTH-1 downto 0);
      Sd_Cmd 					: 	inout		std_logic;
      Sd_Data 					: 	inout		std_logic;
		Sd_Clk					:	out		std_logic;
		Start						:	in			std_logic;
		New_State				:	out		std_logic;
		Cmd_Prev_Rx				: 	out		std_logic_vector(47 downto 0);
		Cmd_Prev_Tx				: 	out		std_logic_vector(CMD_LENGTH-1 downto 0);
		Resp_Found				:	out		std_logic;
		Proceed					:	in			std_logic;
		State_Prog				:	in			std_logic;
		Received					:	out		std_logic;
		Sent_Cmd					:	out		std_logic;
		Rec_Resp					:	out		std_logic;
		Data_Rec					:	out		std_logic;
		Data_Sent				:	out		std_logic;
		Data_Read_Out			:	out		std_logic_vector(255 downto 0);
		Data_Ready				:	out		std_logic;
		Rca_Out					:	out		std_logic_vector(15 downto 0)
	);
end component;


---- constants
constant DATA_INPUT_WIDTH		:		integer := 8;


---- signals

signal dout 				: 		std_logic_vector(7 downto 0) := X"30";
signal din					:		std_logic_vector(7 downto 0);
signal data_present_rx	:		std_logic := '0';
signal data_present_tx	:		std_logic := '0';
signal data_present_cmd	:		std_logic := '0';
signal data_present_resp:		std_logic := '0';
signal en_16_x_baud		:		std_logic;
signal baud_count 		: 		signed(9 downto 0) := (others => '0');
signal buffer_full		:		std_logic;
signal load_reg			:		std_logic := '0';

signal data_in				:		std_logic_vector(DATA_INPUT_WIDTH-1 downto 0);
signal clk_sd				:		std_logic;
signal start				:		std_logic;
signal new_state			:		std_logic;
signal prev_cmd_rx		:		std_logic_vector(47 downto 0) := (others => '0');
signal prev_cmd_tx		:		std_logic_vector(5 downto 0) := (others => '0');

-- clock signals 
signal clk_96				:		std_logic := '0';
signal clk_50				:		std_logic := '0';
signal clk_sd_pass		:		std_logic := '0';

signal cmd_rx_count		:		integer range 0 to 53;
signal cmd_tx_count		:		integer range 0 to 5;
signal rx_reg				:		std_logic_vector(53 downto 0);
signal prev_data_present:		std_logic;

signal serial_done		:		std_logic := '1';		-- indicates that serial sent, hold high	
signal prog_state			:		std_logic := '0';
signal sent_cmd			:		std_logic := '0';
signal rec_resp			:		std_logic := '0';
signal sent_cmd_reg		:		std_logic_vector(1 downto 0) := "00";
signal rec_resp_reg		:		std_logic_vector(1 downto 0) := "00";

signal current_bit_c		:		integer range 0 to 6 := 6;
signal delay_count_c		:		integer range 0 to 192;
signal send_c				:		std_logic := '0';
signal current_bit_r		:		integer range 0 to 48 := 48;
signal delay_count_r		:		integer range 0 to 192;
signal send_r				:		std_logic := '0';

signal sent_data			:		std_logic;
signal rec_data			:		std_logic;
signal rec_data_reg		:		std_logic_vector(1 downto 0) := "00";

signal data_found			:		std_logic;
signal data_read			:		std_logic_vector(255 downto 0);
signal send_d				:		std_logic := '0';
signal current_bit_d		:		integer range 0 to 256 := 256;
signal delay_count_d		:		integer range 0 to 192;
signal rca					:		std_logic_vector(15 downto 0);
signal send_rca			:		std_logic;
signal current_bit_rca	:		integer range 0 to 16;
signal delay_count_rca	:		integer range 0 to 192;
signal received			:		std_logic;

begin

baud_timer: process(clk_96)
begin
	if rising_edge(clk_96) then
		if baud_count="1001110000" then
			baud_count <= (others => '0');
			en_16_x_baud <= '1';
		else
			baud_count <= baud_count + "0000000001";
			en_16_x_baud <= '0';
		end if;
	end if;
end process baud_timer;

--------------------------------------------------------------------------------------------
-- find user command to proceed to next state and flag
RX_PROG : process(clk_96) is
begin

	if rising_edge(clk_96) then
	
		if din = X"20" and data_present_rx = '1' then
			prog_state <= '1';
		else
			if received = '1' then
				prog_state <= '0';
			end if;
		end if;
	end if;
	
end process RX_PROG;

--------------------------------------------------------------------------------------------
-- find user command to print command
RX_RESP : process(clk_96) is
begin

	if rising_edge(clk_96) then
	
		if data_present_rx = '1' then
			-- if prompt recived print previous command
			if din = X"63" then		-- 0X63 = 'c'
				send_c <= '1';
			end if;
			
			-- if prompt recived print previous command
			if din = X"72" then		-- 0X72 = 'r'
				send_r <= '1';
			end if;
			
			-- if prompt recived print rca
			if din = X"61" then		-- 0X72 = 'r'
				send_rca <= '1';
			end if;
		end if;
		
		if data_found = '1' then
			send_d <= '1';
		end if;
		
		if send_c = '1' then
			-- loop through each bit in command
			if current_bit_c = 0 then
				current_bit_c <= 6;
				send_c <= '0';
				dout <= X"2D";
				data_present_tx <= '1';	
			else
				-- after delay for previous bit, send next bit
				if delay_count_c = 192 then
					delay_count_c <= 0;
					
					-- select correct ASCII value
					if prev_cmd_tx(current_bit_c-1) = '1' then
						dout <= X"31";					-- 0X31 = '1'
					else 
						dout <= X"30";					-- 0X30 = '0'
					end if;

					data_present_tx <= '1';
					current_bit_c <= current_bit_c - 1;
				else
					data_present_tx <= '0';
					
					if en_16_x_baud = '1' then
						delay_count_c <= delay_count_c + 1;
					end if;
				end if;
			end if;
		elsif send_r = '1' then
			-- loop through each bit in command
			if current_bit_r = 0 then
				current_bit_r <= 48;
				send_r <= '0';
				dout <= X"2D";
				data_present_tx <= '1';
			else
				-- after delay for previous bit, send next bit
				if delay_count_r = 192 then
					delay_count_r <= 0;
					
					-- select correct ASCII value
					if prev_cmd_rx(current_bit_r-1) = '1' then
						dout <= X"31";					-- 0X31 = '1'
					else 
						dout <= X"30";					-- 0X30 = '0'
					end if;
					
					data_present_tx <= '1';
					current_bit_r <= current_bit_r - 1;
				else
					data_present_tx <= '0';
					
					if en_16_x_baud = '1' then
						delay_count_r <= delay_count_r + 1;
					end if;
				end if;
			end if;
		elsif send_d = '1' then
			-- loop through each bit in command
			if current_bit_d = 0 then
				current_bit_d <= 256;
				send_d <= '0';
				dout <= X"2D";
				data_present_tx <= '1';
			else
				-- after delay for previous bit, send next bit
				if delay_count_d = 192 then
					delay_count_d <= 0;
					
					-- select correct ASCII value
					if data_read(current_bit_d-1) = '1' then
						dout <= X"31";					-- 0X31 = '1'
					else 
						dout <= X"30";					-- 0X30 = '0'
					end if;
					
					data_present_tx <= '1';
					current_bit_d <= current_bit_d - 1;
				else
					data_present_tx <= '0';
					
					if en_16_x_baud = '1' then
						delay_count_d <= delay_count_d + 1;
					end if;
				end if;
			end if;
		elsif send_rca = '1' then
			-- loop through each bit in command
			if current_bit_rca = 0 then
				current_bit_rca <= 16;
				send_rca <= '0';
				dout <= X"2D";
				data_present_tx <= '1';
			else
				-- after delay for previous bit, send next bit
				if delay_count_rca = 192 then
					delay_count_rca <= 0;
					
					-- select correct ASCII value
					if rca(current_bit_rca-1) = '1' then
						dout <= X"31";					-- 0X31 = '1'
					else 
						dout <= X"30";					-- 0X30 = '0'
					end if;
					
					data_present_tx <= '1';
					current_bit_rca <= current_bit_rca - 1;
				else
					data_present_tx <= '0';
					
					if en_16_x_baud = '1' then
						delay_count_rca <= delay_count_rca + 1;
					end if;
				end if;
			end if;
		elsif sent_cmd_reg = "01" then 
			dout <= X"43";					-- 0X43 = 'C'
			data_present_tx <= '1';
		elsif rec_resp_reg = "01" then 
			dout <= X"52";					-- 0X52 = 'R'
			data_present_tx <= '1';
		elsif rec_data_reg = "01" then
			dout <= X"44";
			data_present_tx <= '1';
		else
			data_present_tx <= '0';
		end if;
		
		-- shift sent signals
		sent_cmd_reg <= sent_cmd_reg(0) & sent_cmd;
		rec_resp_reg <= rec_resp_reg(0) & rec_resp;
		rec_data_reg <= rec_data_reg(0) & rec_data;
		
	end if;	
end process RX_RESP;

Sd_Clk_Out <= clk_sd_pass;

--------------------------------------------------------------------------------------------
-- component instantiation

INST_DCM32TO96	: DCM32TO96 
port map
(
		CLKIN_IN 				=> Clk_Ext,
		RST_IN 					=> '0',
		CLKFX_OUT 				=> clk_96,
		CLK0_OUT 				=> open,
		LOCKED_OUT 				=> open
);

INST_DCM32TO50	: DCM32TO50
port map
(
		CLKIN_IN 				=> Clk_Ext,
		RST_IN 					=> '0',
		CLKFX_OUT 				=> clk_50,
		CLK0_OUT 				=> open,
		LOCKED_OUT 				=> open
);

INST_UART_TX : uart_tx
port map 
(
		data_in 					=> dout,
		write_buffer 			=> data_present_tx,
		reset_buffer 			=> '0',
		en_16_x_baud 			=> en_16_x_baud,
		clk 						=> clk_96,
		serial_out 				=> Tx,
		buffer_half_full 		=> open,
		buffer_full 			=> buffer_full
);

INST_UART_RX : uart_rx
port map 
(
		serial_in 				=> Rx,
		read_buffer 			=> '1',
		reset_buffer 			=> '0',
		en_16_x_baud 			=> en_16_x_baud,
		clk 						=> clk_96,
		data_out 				=> din,
		buffer_data_present 	=> data_present_rx,
		buffer_half_full 		=> open,
		buffer_full 			=> open
);

SD_HOST : host
port map 
( 
		Clk 						=> clk_50,
		Reset						=>	Reset,
      Data 						=> data_in,
      Sd_Cmd 					=> sd_cmd,
      Sd_Data 					=> sd_data,
		Sd_Clk					=> clk_sd_pass,
		Start						=>	start,
		New_State				=>	new_state,
		Cmd_Prev_Rx				=> prev_cmd_rx,
		Cmd_Prev_Tx				=> prev_cmd_tx,
		Resp_Found				=> Resp_Found,
		Proceed					=>	Serial_Done,
		State_Prog				=> prog_state,
		Received					=> received,
		Sent_Cmd					=>	sent_cmd,
		Rec_Resp					=>	rec_resp,
		Data_Rec					=> rec_data,
		Data_Sent				=> sent_data,
		Data_Read_Out			=>	data_read,
		Data_Ready				=>	data_found,
		Rca_Out					=>	rca
);

Data_Done <= sent_data;


end behavioral;

